/** @file
  This driver installs SMBIOS information for ARM Juno platforms

  Copyright (c) 2015, ARM Limited. All rights reserved.
  Copyright (c) 2006 - 2023, Kunlun BIOS, Kunlun Technology (Beijing) Co., Ltd.. All
  Rights Reserved.

  This program and the accompanying materials
  are licensed and made available under the terms and conditions of the BSD License
  which accompanies this distribution.  The full text of the license may be found at
  http://opensource.org/licenses/bsd-license.php

  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/
#include <ArmPlatform.h>
#include <PiDxe.h>
#include <IndustryStandard/SmBios.h>
#include <Library/ArmLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PrintLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Library/HobLib.h>
#include <OEMSvc.h>
#include <Library/SmbiosPlatformLib.h>


STATIC PHYTIUM_MEMORY_INFOR          *mMemInfor;
STATIC MCU_DIMMS                     *mMcuDimms;

// SMBIOS tables often reference each other using
// fixed constants, define a list of these constants
// for our hardcoded tables


STATIC CPUTYPE mCpuType[] = {
  {0x500, "D2000/8"},
  {0x501, "D2000/8 B8C"},
  {0x502, "D2000/8 E8C"},
  {0x503, "D2000/8 S8C"},
  {0x504, "D2000/8 S8I"},
  {0x505, "D2000/4 S4C"},
  {0x506, "D2000/4 S4I"},
//[jwluo-0002]
  {0x300, "FT2000/4-X"},
//[jwluo-0002]
//[wyj-0005]
  {0x301, "FT2000/4"},
  {0x302, "FT2000/4-S"},
  {0x303, "FT2000/4-I"},
  {0x304, "FT2000/4-SI"},
  {0x305, "FT2000/4-2"},
  {0x306, "FT2000/4-I2"},
  {0x307, "FT2000/4-I1"},
  {0x308, "FT2000/4-M"}
//[wyj-0005]
};

/**
  This function is used for smbios to get cpu info hob.

**/
PHYTIUM_CPU_INFO *
SmbiosGetCpuInfoHob()
{
  EFI_HOB_GUID_TYPE      *GuidHob;
  GuidHob = GetFirstGuidHob(&gPlatformCpuInforGuid);
  if (NULL == GuidHob){
      DEBUG((EFI_D_ERROR, "Could not get Cpuinfo Guid hob.\n"));
      return NULL;
  }
  return (PHYTIUM_CPU_INFO *) GET_GUID_HOB_DATA(GuidHob);
}

/**
  This function is used to get Pci location from dp string.

  @param  NumberOfDevices    A pointer to the number of devices.

**/
STATIC
VOID
SmbiosGetMemoryDevicesNumber (
  IN OUT UINT16 *NumberOfDevices
)
{
  UINT32      Index;
  UINT16      NumberOfMemoryDevices;
  MCU_DIMM    *McuDimm;

  NumberOfMemoryDevices = 0;
  McuDimm = mMcuDimms->McuDimm;
  for(Index = 0; Index < mMcuDimms->MemDimmCount; Index ++){
    if(McuDimm->MemSize) {
      NumberOfMemoryDevices++;
    }
    McuDimm ++;
  }

  *NumberOfDevices = NumberOfMemoryDevices;
}

/**
  This function is used for smbios to get memory capacity.

  @retval Size

**/
STATIC
UINT64
SmbiosGetMemoryCapacity(
)
{
  UINT32        Index;
  UINT64        Size;
  MCU_DIMM      *McuDimm;

  Size = 0;
  McuDimm = mMcuDimms->McuDimm;
  for(Index = 0; Index < mMcuDimms->MemDimmCount; Index ++){
    Size = Size + McuDimm->MemSize;
    McuDimm ++;
  }

  return Size;
}

/**
  This function is used to for smbios to get cpu info.

  @param  SmbiosCpuInfo   A pointer to the smbios platform cpu info.

  @retval EFI_INVALID_PARAMETER
  @retval EFI_SUCCESS

**/
EFI_STATUS
SmbiosGetCpuInfo(
  OUT SMBIOSPLATFORMCPUINFO * SmbiosCpuInfo
 )
{
  EFI_HOB_GUID_TYPE         *GuidHob;
  PHYTIUM_CPU_INFO          *CpuInfo;
  UINTN                     SocketNumber, SocketIndex;
  UINTN                     Index;
  UINT8                     CoreCount;
  UINT16                    CpuFreq;
  CHAR8                     CpuTypeName[100];
  CHAR16                    ProcessorVer[100];
  UINT32                    CacheSize;
  UINTN                     CpuTypeNameSize;

  CoreCount = 0;
  CpuFreq = 0;
  memset(CpuTypeName, 0 ,sizeof(CpuTypeName));
  memset(ProcessorVer, 0 ,sizeof(ProcessorVer));
  
  if(NULL == SmbiosCpuInfo)
  {
    return EFI_INVALID_PARAMETER;
  }
  GuidHob = GetFirstGuidHob(&gPlatformCpuInforGuid);
  if (GuidHob != NULL){

    CpuInfo = (PHYTIUM_CPU_INFO *) GET_GUID_HOB_DATA(GuidHob);
    SocketNumber = CpuInfo->CpuMapInfo.CpuMapCount;
    DEBUG((EFI_D_INFO, "%a() cpumap=%x, cpufreq=%d, cpuversion=%d\n", __FUNCTION__, CpuInfo->CpuMapInfo.CpuMap[0], CpuInfo->CpuCoreInfo.CpuFreq, CpuInfo->CpuVersion));
    for(Index = 0; Index < sizeof(mCpuType)/sizeof(CPUTYPE); Index++) {
      //[jdzhang-0009]>>>
      if(mCpuType[Index].CpuTypeId == CpuInfo->CpuVersion) {
      //[jdzhang-0009]<<<
      CopyMem(CpuTypeName, mCpuType[Index].CpuTypeName, AsciiStrLen(mCpuType[Index].CpuTypeName));
      CpuTypeNameSize = AsciiStrLen(CpuTypeName);
      PcdSetExPtrS ( &gKlSmbiosTokenSpaceGuid, PcdSmbiosStringCpuType, &CpuTypeNameSize, CpuTypeName );
      break;
      }
    }
    for(SocketIndex = 0; SocketIndex < SocketNumber; SocketIndex++) {
      for(Index = 0; Index < 64; Index++) {
        if((CpuInfo->CpuMapInfo.CpuMap[SocketIndex] >> Index) & 0x1) {
          CoreCount++;
        }
      }
    }
    CpuFreq = CpuInfo->CpuCoreInfo.CpuFreq;
    //[jdzhang-0009]>>>
    SmbiosCpuInfo->mCpuTypeId = CpuInfo->CpuVersion;
    //[jdzhang-0009]<<<
    CacheSize = CpuInfo->CpuCoreInfo.CpuL3CacheSize/1024;
  }else{
    DEBUG((EFI_D_ERROR,"%a(),Get cpu info hob failed!Using the value from PCD\n",__FUNCTION__));
    CoreCount = (UINT8)FixedPcdGet32(PcdCoreCount);
    CpuFreq = FixedPcdGet16(PcdKunlunSmbiosType4MaxSpeed);
    UnicodeSPrint(ProcessorVer, sizeof(ProcessorVer),L"Phytium %s/%d",(CHAR16 *)PcdGetPtr(PcdKunlunSmbiosType4ProcessorVersion), CoreCount);
    UnicodeStrToAsciiStrS (ProcessorVer, CpuTypeName, StrLen (ProcessorVer) + 1);
    CacheSize =  PcdGet32(PcdKunlunSmbiosType7L3Size);

  }
  SmbiosCpuInfo->mCpuCount = PcdGet8(PcdKunlunSmbiosType7CPUNUM);
  SmbiosCpuInfo->mCoreCount = CoreCount;
  SmbiosCpuInfo->mCoreMaxFrequency = FixedPcdGet16(PcdKunlunSmbiosType4MaxSpeed);
  SmbiosCpuInfo->mCoreFrequency = CpuFreq;
  CopyMem(SmbiosCpuInfo->mCpuTypeName, CpuTypeName, AsciiStrLen(CpuTypeName)+1);
  SmbiosCpuInfo->mCpuL3CacheSize = CacheSize;

  return EFI_SUCCESS;
}

/**
  This function is used for smbios to get platform info.

  @param  SmbiosPlatInfo   A pointer to the smbios platform info.

  @retval EFI_INVALID_PARAMETER
  @retval Status

**/
EFI_STATUS
SmbiosGetPlatformInfo(
   OUT SMBIOSPLATFORMINFO * SmbiosPlatInfo
)
{
  EFI_STATUS                      Status;

  if(NULL == SmbiosPlatInfo)
  {
      return EFI_INVALID_PARAMETER;
  }
  Status = SmbiosGetCpuInfo(&SmbiosPlatInfo->mCpuInfo);

  return Status;
}

/**
  This function is used for smbios to get memory info.

  @param  SmbiosMemInfo    A pointer to the smbios platform memory info.

  @retval EFI_INVALID_PARAMETER
  @retval EFI_SUCCESS

**/
EFI_STATUS
SmbiosGetMemInfo(
  OUT SMBIOSPLATFORMMEMINFO * SmbiosMemInfo
 )
{
  EFI_HOB_GUID_TYPE     *GuidHob;
  UINTN                      Size;
  UINT16                     NumberOfDevices;

  if(NULL == SmbiosMemInfo)
  {
    return EFI_INVALID_PARAMETER;
  }

  GuidHob = GetFirstGuidHob(&gPlatformMemoryInforGuid);
  if (NULL == GuidHob){
      DEBUG((EFI_D_ERROR, "Could not get MemoryMap Guid hob.\n"));
      return EFI_NOT_FOUND;
  }
  mMemInfor = (PHYTIUM_MEMORY_INFOR *) GET_GUID_HOB_DATA(GuidHob);
  Size    = sizeof (mMemInfor->MemBlockCount) + sizeof (MEMORY_BLOCK) * mMemInfor->MemBlockCount;
  mMcuDimms = (MCU_DIMMS *)((UINTN)mMemInfor + Size);
  SmbiosGetMemoryDevicesNumber(&NumberOfDevices);
  SmbiosMemInfo->mNumberOfDevices = NumberOfDevices;
  SmbiosMemInfo->mSize = SmbiosGetMemoryCapacity();

  return EFI_SUCCESS;
}


